package cn.aion.crawlers;

import cn.aion.dao.AnchorChannelDAO;
import cn.aion.dao.AnchorDataDAO;
import cn.aion.model.AnchorChannel;
import cn.aion.model.AnchorData;
import cn.aion.model.BilibiliInfo;
import cn.aion.util.HttpClientHelper;
import cn.aion.util.Helper;
import cn.wanghaomiao.seimi.annotation.Crawler;
import cn.wanghaomiao.seimi.def.BaseSeimiCrawler;
import cn.wanghaomiao.seimi.struct.Request;
import cn.wanghaomiao.seimi.struct.Response;
import cn.wanghaomiao.xpath.model.JXDocument;
import cn.wanghaomiao.xpath.model.JXNode;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 搜索全频道数据：腾讯视频
 * Created by 虚空之翼 on 2017/1/2.
 */
@Crawler(name = "search", useUnrepeated = false, delay = 5)
public class Search extends BaseSeimiCrawler {
    @Autowired
    private AnchorChannelDAO anchorChannelDAO;
    @Autowired
    private AnchorDataDAO anchorDataDAO;

    @Value("${seimiAgentHost}")
    private String seimiAgentHost;
    @Value("${seimiAgentPort}")
    private int seimiAgentPort;
    @Override
    public String seimiAgentHost() { return this.seimiAgentHost; }
    @Override
    public int seimiAgentPort() { return this.seimiAgentPort; }

    @Override
    public String[] startUrls() {
        //两个是测试去重的
        return new String[]{"http://www.van-cool.com/admin/base/scan"};
    }

    @Override
    public void start(Response response) {
        main();
    }

    @Scheduled(cron = "0 0 15,19,23 * * ?")
    public void main() {
        try {
            int start = 0;
            int total = 100;
            int p = 1;
            do {
                start = (p - 1) * total;
                List<AnchorChannel> channels = anchorChannelDAO.selectAll(start, total);
                total = channels.size();
                p++;
                logger.info("总数：{}，第一个值：{}|{}", total, channels.get(0).getId(), channels.get(0).getName());
                for (AnchorChannel channel : channels) {
                    Map<String, String> metas = new HashMap<String, String>() {
                        {
                            put("channelId", String.valueOf(channel.getId()));
                        }
                    };
                    // 统计腾讯视频数据
                    String qqUrl = channel.getQqUrl();
                    if (qqUrl != null && !qqUrl.isEmpty()) {
                        Request request = Request.build(qqUrl, "channelQQ");
                        request.setMeta(metas);
                        push(request);
                    } else {
                        if (channel.getIsSearch() == 0) {
                            qqUrl = "https://v.qq.com/x/search/?q=" + channel.getName();
                            Request request = Request.build(qqUrl, "searchQQ");
                            request.setMeta(metas);
                            push(request);
                        }
                    }
                    // 统计爱奇艺视频数据
                    String iqiyiUrl = channel.getIqiyiUrl();
                    if (iqiyiUrl != null && !iqiyiUrl.isEmpty()) {
                        Request request = Request.build(iqiyiUrl, "channelIqiyi");
                        request.setMeta(metas);
                        push(request);
                    } else {
                        if (channel.getIsSearch() == 0) {
                            iqiyiUrl = "http://so.iqiyi.com/so/q_" + channel.getName();
                            Request request = Request.build(iqiyiUrl, "searchIqiyi");
                            request.setMeta(metas);
                            push(request);
                        }
                    }
                    // 统计搜狐视频数据
                    String sohuUrl = channel.getSohuUrl();
                    if (sohuUrl != null && !sohuUrl.isEmpty()) {
                        String id = sohuUrl.substring(sohuUrl.lastIndexOf("/") + 1);
                        String fansUrl = "http://push.my.tv.sohu.com/user/a/fa/count.do?uids=" + id;
                        String playUrl = "http://vstat.v.blog.sohu.com/usr/usrSumCount.action?uid=" + id;

                        Request request = Request.build(fansUrl, "searchSohuFans");
                        request.setMeta(metas);
                        push(request);
                        searchSohuPlay(playUrl, channel.getId());
                    } else {
                        if (channel.getIsSearch() == 0) {
                            sohuUrl = "http://so.tv.sohu.com/mts?wd=" + channel.getName();
                            Request request = Request.build(sohuUrl, "searchSohu");
                            request.setMeta(metas);
                            push(request);
                        }
                    }
                    // 统计B站视频数据,todo IP扫描限制
//                    String bilibiliUrl = channel.getBilibiliUrl();
//                    if (bilibiliUrl != null && !bilibiliUrl.isEmpty()) {
//                        channelBiliBili(bilibiliUrl, channel.getId());
//                    } else {
//                        if (channel.getIsSearch() == 0) {
//                            bilibiliUrl = "http://search.bilibili.com/upuser?keyword=" + channel.getName();
//                            Request request = Request.build(bilibiliUrl, "searchBiliBili");
//                            request.setMeta(metas);
//                            push(request);
//                        }
//                    }

                }

                Thread.sleep(5000);
//            } while (p <= 1);
            } while (total == 100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * https://v.qq.com/x/search/?q=%E7%B1%BD%E5%B2%B7
     */
    public void searchQQ(Response response) {
        JXDocument doc = response.document();

        String channelId = Helper.getMetaChannelId(response.getMeta());
        try {
            List<JXNode> searchDoc = doc.selN("//div[@class='result_item result_item_vplus']");
            if (!searchDoc.isEmpty()) {
                String url = StringUtils.join(searchDoc.get(0).sel("//a[@class='figure result_figure']/@href"),"");
                String name = response.getUrl().substring(response.getUrl().indexOf("=")+1);
                logger.info("搜索腾讯频道：{}，链接：{}", name, url);
                Request request = Request.build(url, "searchQQRefresh");
                Map<String,String> metas = new HashMap<String, String>() { {
                    put("channelId", String.valueOf(channelId));
                } };
                request.setMeta(metas);
                push(request);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 腾讯频道跳转
     */
    public void searchQQRefresh(Response response) {
        String channelId = Helper.getMetaChannelId(response.getMeta());
        String url = response.getRealUrl();
        if (response.getRealUrl().indexOf("%22") != 0) {
            url = response.getRealUrl().substring(0, response.getRealUrl().indexOf("%22"));
        }

        Request request = Request.build(url, "channelQQ");
        Map<String,String> metas = new HashMap<String, String>() { {
            put("channelId", String.valueOf(channelId));
        } };
        request.setMeta(metas);
        push(request);
        // 更新URL链接
        anchorChannelDAO.updateQQUrl(url, Integer.parseInt(channelId));
    }

    /**
     * 腾讯视频频道主页
     */
    public void channelQQ(Response response) {
        JXDocument doc = response.document();
        String channelId = Helper.getMetaChannelId(response.getMeta());
        String url = response.getUrl();
        try {
            String name = StringUtils.join(doc.sel("//p[@class='user_name']/span/text()"),"");
            String fansCount = StringUtils.join(doc.sel("//ul[@class='user_count']/li/span[@class='num j_rss_count']/text()"),"");
            String playCount = StringUtils.join(doc.sel("//ul[@class='user_count']/li[last()]/span[@class='num']/text()"),"");
            logger.info("腾讯频道：{}，播放：{}，订阅：{}，链接：{}", name, playCount, fansCount, url);

            // 更新总数和每日扫描记录
            int id = Integer.parseInt(channelId);
            int fans = Helper.caseFansTotal(fansCount);
            Long play = Helper.casePlayTotal(playCount);
            anchorChannelDAO.updateQQTotal(id, play, fans);
            updateDate(id, play, fans, 4);
            anchorChannelDAO.updateTotal(Integer.parseInt(channelId));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * http://so.iqiyi.com/so/q_籽岷
     */
    public void searchIqiyi(Response response) {
        JXDocument doc = response.document();
        String channelId = Helper.getMetaChannelId(response.getMeta());
        try {
            List<JXNode> searchDoc = doc.selN("//div[@class='mod_result']/ul/li[@data-widget-searchlist-tvid=0]");
            if (!searchDoc.isEmpty()) {
                String subTitle = StringUtils.join(searchDoc.get(0).sel("//h3/span/a/html()"),"");
                if (!subTitle.equals("")) {
                    String url = searchDoc.get(0).sel("//h3/a/@href").get(0).toString();
                    String name = StringUtils.join(searchDoc.get(0).sel("//h3/a/@title"),"");
                    logger.info("搜索爱奇艺频道：{}，链接：{}", name, url);

                    AnchorChannel channel = anchorChannelDAO.selectOneByName(name);
                    Request request = Request.build(url, "channelIqiyi");
                    Map<String,String> metas = new HashMap<String, String>();
                    metas.put("channelId", channelId);
                    request.setMeta(metas);
                    push(request);
                    // 更新URL链接
                    anchorChannelDAO.updateIqiyiUrl(url, Integer.parseInt(channelId));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * http://www.iqiyi.com/u/1240942424
     */
    public void channelIqiyi(Response response) {
        JXDocument doc = response.document();
        String channelId = Helper.getMetaChannelId(response.getMeta());
        try {
            String name = StringUtils.join(doc.sel("//div[@class='pf_username']/span/text()"),"");
            String name2 = StringUtils.join(doc.sel("//div[@class='titleCustom-user']/div/h3[@class='ctom-til']/a[first()]/@title"),"");
            String name3 = StringUtils.join(doc.sel("//div[@class='detail_name']/h2/a/text()"),"");
            if (!name2.equals("")) {
                name = name2;
            } else if(!name3.equals("")) {
                name = name3;
            }
            String fansCount = StringUtils.join(doc.sel("//div[@class='info_connect']/span[first()]/em/a/text()"),"");
            String fansCount2 = StringUtils.join(doc.sel("//div[@class='pc-main-side']/div/div/div[@data-ugcmoveposition-id=7]/h2/a/span/text()"),"");
            if (!fansCount2.equals("")) { fansCount = fansCount2; }
            String playCount = StringUtils.join(doc.sel("//div[@class='info_connect']/span[@class='conn_type S_line1']/em/a/text()"),"");
            String playCount2 = StringUtils.join(doc.sel("//div[@class='num_item']/a[last()]/i/text()"),"");
            if (!playCount2.equals("")) { playCount = playCount2; }
            String videoCount = StringUtils.join(doc.sel("//div[@class='info_connect']/span[last()]/em/a/text()"),"");

            logger.info("爱奇艺频道：{}，播放：{}，订阅：{}，链接：{}", name, playCount, fansCount, response.getUrl());
            if (!name.equals("")) {
                // 更新总数和每日扫描记录
//              AnchorChannel channel = anchorChannelDAO.selectOne(Integer.parseInt(channelId));
                int id = Integer.parseInt(channelId);
                Long play = Helper.casePlayTotal(playCount);
                int fans = Helper.caseFansTotal(fansCount);
                anchorChannelDAO.updateIqiyiTotal(id, play, fans);
                updateDate(id, play, fans, 2);
                anchorChannelDAO.updateTotal(Integer.parseInt(channelId));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * http://so.tv.sohu.com/mts?wd=籽岷
     * http://push.my.tv.sohu.com/user/a/fa/count.do?uids=278874491
     * http://vstat.v.blog.sohu.com/usr/usrSumCount.action?uid=278874491
     */
    public void searchSohu(Response response) {
        JXDocument doc = response.document();
        String channelId = Helper.getMetaChannelId(response.getMeta());
        try {
            String name = StringUtils.join(doc.sel("//div[@class='area']/li[first()]/div/div/div/div/a/@title"),"");
            String sohuUrl = StringUtils.join(doc.sel("//div[@class='area']/li[1]/div/div/div/div[1]/a/@href"),"");
            if (!name.equals("")) {
                logger.info("搜索搜狐频道：{}，链接：{}", name, sohuUrl);
                String id = sohuUrl.substring(sohuUrl.lastIndexOf("/")+1);
                String fansUrl = "http://push.my.tv.sohu.com/user/a/fa/count.do?uids=" + id;
                String playUrl = "http://vstat.v.blog.sohu.com/usr/usrSumCount.action?uid=" + id;

                // 获取数据，订阅和播放数分开抓取
                Map<String,String> metas = new HashMap<String, String>() { {
                    put("channelId", String.valueOf(channelId));
                } };
                Request request = Request.build(fansUrl, "searchSohuFans");
                request.setMeta(metas);
                push(request);
                searchSohuPlay(playUrl, Integer.parseInt(channelId));

                // 更新URL链接
                if (!sohuUrl.contains("http:")) { sohuUrl = "http:" + sohuUrl; }
                anchorChannelDAO.updateSohuUrl(sohuUrl, Integer.parseInt(channelId));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void searchSohuFans(Response response) {
        String channelId = Helper.getMetaChannelId(response.getMeta());
        String result = response.getContent();
        String count = result.substring(result.indexOf("fansCount")+11);
        count = count.substring(0, count.indexOf(","));

        logger.info("搜狐频道：{}，订阅：{}，链接：{}", channelId, count, response.getUrl());
        int id = Integer.parseInt(channelId);
        int fans = Integer.parseInt(count);
        anchorChannelDAO.updateSohuFans(id, fans);
        updateDate(id, 0L, fans, 3);
        anchorChannelDAO.updateTotal(Integer.parseInt(channelId));
    }

    public void searchSohuPlay(String url, int channelId) {
        String result = HttpClientHelper.setHttpGet(url);
        String count = result.substring(result.indexOf("count")+7, result.lastIndexOf("}"));
        if (!count.equals("")) {
            logger.info("搜狐频道：{}，播放数：{}，链接：{}", channelId, count, url);
            Long play = Long.parseLong(count);
            anchorChannelDAO.updateSohuPlay(channelId, play);
            updateDate(channelId, play, 0, 3);
            anchorChannelDAO.updateTotal(channelId);
        }
    }

    /**
     * http://search.bilibili.com/upuser?keyword=籽岷
     * http://space.bilibili.com/686127/#!/index
     */
    public void searchBiliBili(Response response) {
        JXDocument doc = response.document();
        String channelId = Helper.getMetaChannelId(response.getMeta());
        String keyword = response.getUrl().substring(response.getUrl().lastIndexOf("=")+1);
        try {
            String name = StringUtils.join(doc.sel("//li[@class='special']/a/@title"),"");
            String url = StringUtils.join(doc.sel("//li[@class='special']/a/@href"),"");
            // 可能存在多个类似的UP主存在
            if (!name.equals("") && name.equals(keyword)) {
                if (!url.contains("http:")) { url = "http:" + url; }
                if (url.contains("?")) { url = url.substring(0, url.indexOf("?")); }
                logger.info("搜索B站频道：{}，链接：{}", name, url);
                anchorChannelDAO.updateBilibiliUrl(url, Integer.parseInt(channelId));
                channelBiliBili(url, Integer.parseInt(channelId));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void channelBiliBili(String url, int channelId) {
        String uid = url.substring(url.lastIndexOf("/") + 1);
        Map<String,String> params = new HashMap<String, String>();
        params.put("mid", uid);
        BilibiliInfo result = HttpClientHelper.setBiliBiliPost(params);
        if (result != null) {
            // 更新总数和每日扫描记录
            Long play = result.getData().getPlayNum();
            int fans = result.getData().getFans();
            logger.info("B站频道：{}，播放：{}，订阅：{}，链接：{}", uid, play, fans, url);
            anchorChannelDAO.updateBilibiliTotal(channelId, play, fans);
            anchorChannelDAO.updateTotal(channelId);

            updateDate(channelId, play, fans, 5);
        }
    }

    /**
     * 1优酷、2爱奇艺、3搜狐、4腾讯、5B站
     * @param channelId 频道ID
     * @param playTotal 播放
     * @param fansTotal 订阅
     * @param type  类型
     */
    public void updateDate(int channelId, Long playTotal, int fansTotal, int type) {
        // 计算增量
        Long playAdd = 0l;
        int fansAdd = 0;
        AnchorData preAnchorData = anchorDataDAO.selectOnePrevious(channelId);
        if (preAnchorData != null) {
            switch (type) {
                case 1:
                    playTotal = playTotal != 0 ? playTotal : preAnchorData.getYoukuPlayTotal();
                    fansTotal = fansTotal != 0 ? fansTotal : preAnchorData.getYoukuFansTotal();
                    playAdd = playTotal - preAnchorData.getYoukuPlayTotal();
                    fansAdd = fansTotal - preAnchorData.getYoukuFansTotal();
                    break;
                case 2:
                    playTotal = playTotal != 0 ? playTotal : preAnchorData.getIqiyiPlayTotal();
                    fansTotal = fansTotal != 0 ? fansTotal : preAnchorData.getIqiyiFansTotal();
                    playAdd = playTotal - preAnchorData.getIqiyiPlayTotal();
                    fansAdd = fansTotal - preAnchorData.getIqiyiFansTotal();
                    break;
                case 3:
                    playTotal = playTotal != 0 ? playTotal : preAnchorData.getSohuPlayTotal();
                    fansTotal = fansTotal != 0 ? fansTotal : preAnchorData.getSohuFansTotal();
                    playAdd = playTotal - preAnchorData.getSohuPlayTotal();
                    fansAdd = fansTotal - preAnchorData.getSohuFansTotal();
                    break;
                case 4:
                    playTotal = playTotal != 0 ? playTotal : preAnchorData.getQqPlayTotal();
                    fansTotal = fansTotal != 0 ? fansTotal : preAnchorData.getQqFansTotal();
                    playAdd = playTotal - preAnchorData.getQqPlayTotal();
                    fansAdd = fansTotal - preAnchorData.getQqFansTotal();
                    break;
                case 5:
                    playTotal = playTotal != 0 ? playTotal : preAnchorData.getBilibiliPlayTotal();
                    fansTotal = fansTotal != 0 ? fansTotal : preAnchorData.getBilibiliFansTotal();
                    playAdd = playTotal - preAnchorData.getBilibiliPlayTotal();
                    fansAdd = fansTotal - preAnchorData.getBilibiliFansTotal();
                    break;
                default: break;
            }
        } else {
            playAdd = playTotal;
            fansAdd = fansTotal;
        }
//        playTotal,playAdd,fansTotal,fansAdd
        // 添加统计信息
        AnchorData todayAnchorData = anchorDataDAO.selectOneToday(channelId);
        if (todayAnchorData == null) {
            AnchorData data = new AnchorData();
            data.setChannelId(channelId);
            switch (type) {
                case 2:
                    data.setIqiyiPlayTotal(playTotal);
                    data.setIqiyiPlayAdd(playAdd);
                    data.setIqiyiFansTotal(fansTotal);
                    data.setIqiyiFansAdd(fansAdd);
                    anchorDataDAO.saveIqiyi(data);
                    break;
                case 3:
                    data.setSohuPlayTotal(playTotal);
                    data.setSohuPlayAdd(playAdd);
                    data.setSohuFansTotal(fansTotal);
                    data.setSohuFansAdd(fansAdd);
                    anchorDataDAO.saveSohu(data);
                    break;
                case 4:
                    data.setQqPlayTotal(playTotal);
                    data.setQqPlayAdd(playAdd);
                    data.setQqFansTotal(fansTotal);
                    data.setQqFansAdd(fansAdd);
                    anchorDataDAO.saveQQ(data);
                    break;
                case 5:
                    data.setBilibiliPlayTotal(playTotal);
                    data.setBilibiliPlayAdd(playAdd);
                    data.setBilibiliFansTotal(fansTotal);
                    data.setBilibiliFansAdd(fansAdd);
                    anchorDataDAO.saveBilibili(data);
                    break;
                default: break;
            }
        } else {
            switch (type) {
                case 2:
                    todayAnchorData.setIqiyiPlayTotal(playTotal);
                    todayAnchorData.setIqiyiPlayAdd(playAdd);
                    todayAnchorData.setIqiyiFansTotal(fansTotal);
                    todayAnchorData.setIqiyiFansAdd(fansAdd);
                    anchorDataDAO.updateIqiyi(todayAnchorData);
                    break;
                case 3:
                    todayAnchorData.setSohuPlayTotal(playTotal);
                    todayAnchorData.setSohuPlayAdd(playAdd);
                    todayAnchorData.setSohuFansTotal(fansTotal);
                    todayAnchorData.setSohuFansAdd(fansAdd);
                    anchorDataDAO.updateSohu(todayAnchorData);
                    break;
                case 4:
                    todayAnchorData.setQqPlayTotal(playTotal);
                    todayAnchorData.setQqPlayAdd(playAdd);
                    todayAnchorData.setQqFansTotal(fansTotal);
                    todayAnchorData.setQqFansAdd(fansAdd);
                    anchorDataDAO.updateQQ(todayAnchorData);
                    break;
                case 5:
                    todayAnchorData.setBilibiliPlayTotal(playTotal);
                    todayAnchorData.setBilibiliPlayAdd(playAdd);
                    todayAnchorData.setBilibiliFansTotal(fansTotal);
                    todayAnchorData.setBilibiliFansAdd(fansAdd);
                    anchorDataDAO.updateBilibili(todayAnchorData);
                    break;
                default: break;
            }

            // 更新总数
            anchorDataDAO.updateTotal(todayAnchorData.getId());
        }
    }
}
